package com.etlmaster.executor;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.Map;

import com.etlmaster.executor.utils.DpExecutorUtils;
import com.etlmaster.executor.utils.JsonHelper;
import com.etlmaster.executor.utils.LogWriter;
import com.etlmaster.executor.utils.StepState;
import com.etlmaster.executor.utils.StringUtils;
import com.etlmaster.jdbc.JdbcTemplate;

public abstract class StepMeta  implements Cloneable{
	
	private String id;
	
	private String name;
	
	private String step_code;
	
	private String session_id;
	
	private boolean isRootStep = false;
	
	private StepState stepState;
	
	private boolean useConfigTable=true;//是否使用配置表加载参数

	protected int redo=0;//重做次数，0表示不重做直接报错
	
	protected int redoIntervalSeconds = 30;//重做间隔
	
	private boolean skipFlag=false;
	
	public StepMeta(String id, String name,String step_code, String sessionId, String paramStr){
		this.id=id;
		this.name=name;
		this.step_code=step_code;
		this.setSession_id(sessionId);
		this.stepState = new StepState(sessionId,id);
		parseParam(paramStr);//会被子类的属性初始化覆盖，放在子类的构造器中
		if(useConfigTable){
			loadParamsFromConfigTable();
		}
	}
	protected void init() throws EtlMasterException{
		
	}
	
	public void log(String ...args){
		LogWriter.addLog((String) this.getVariable("f"), 0, args);
	}
	/**
	 * 从配置表加载参数
	 */
	protected abstract void loadParamsFromConfigTable();
	
	public <T> T getStep(){
		String className = this.getClass().getName().replaceAll("Meta", "");
//		LOG.debug("Step Class name is {}",className);
		try {
			Class<T> cls = (Class<T>) Class.forName(className);
			Constructor<Step> constructor =  (Constructor<Step>) cls.getConstructor(StepMeta.class);	
			return (T) constructor.newInstance(this);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return null;
	}

	protected void parseParam(String paramStr){
		if(paramStr!=null && paramStr.length()>0){
			paramStr = paramStr.replaceAll("[\\t\\n]","");
			char firstChar = paramStr.charAt(0);
			if(firstChar=='[' || firstChar=='{'){//代表是json对象
				
				Map<String,Object> paramMap = (Map<String,Object>)JsonHelper.getInstance().read(paramStr);
				for (Iterator iterator = paramMap.entrySet().iterator(); iterator.hasNext();) {
					Class cls = this.getClass();
					Map.Entry<String, Object> entry = (Map.Entry<String, Object>) iterator.next();
					
					String key = entry.getKey();
					Field field = null;
					while (field == null) {
						try {
							field = cls.getDeclaredField(key);//这个类的声明中定义的指定名称的属性，这个属性必须是在这个类的声明中定义，可以使私有和保护的,但是所有父类的属性都不会被返回
							if( field!=null ){
								field.setAccessible(true);
								if((field.getType() == Boolean.class || field.getType() == boolean.class)&& entry.getValue().toString().equalsIgnoreCase("true")){
									field.set(this, true);
								}else if((field.getType() == int.class || field.getType() == Integer.class) && (entry.getValue().getClass()==String.class && StringUtils.isNumberic(entry.getValue().toString()))){
									field.set(this, Integer.valueOf(entry.getValue().toString()));
								}else if((field.getType() == double.class || field.getType() == Double.class) && (entry.getValue().getClass()==String.class && StringUtils.isNumberic(entry.getValue().toString()))){
									field.set(this, Double.valueOf(entry.getValue().toString()));
								}else if((field.getType() == long.class || field.getType() == Long.class) && (entry.getValue().getClass()==String.class && StringUtils.isNumberic(entry.getValue().toString()))){
									field.set(this, Long.valueOf(entry.getValue().toString()));
								}else if(field.getType().isInstance(entry.getValue())){
									field.set(this, entry.getValue());
								}
							}
						} catch (NoSuchFieldException e) {
//						e.printStackTrace();
						} catch (SecurityException e) {
							e.printStackTrace();
						} catch (IllegalArgumentException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						}finally{
							cls = cls.getSuperclass();
							if(cls.getName().equals("java.lang.Object") ){
								break;
							}
						}
					}
				}
			}
		}
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public Map<String, Object> getVariables() {
		return JobPool.getVariable(getSession_id());
	}
	public Object getVariable(String key){
		return JobPool.getVariable(getSession_id()).get(key);
	}

	public StepState getStepState() {
		return stepState;
	}

	public void setStepState(StepState stepState) {
		this.stepState = stepState;
	}
	
	public boolean isUseConfigTable() {
		return useConfigTable;
	}
	
	public void setUseConfigTable(boolean useConfigTable) {
		this.useConfigTable = useConfigTable;
	}
	
	public int getRedo() {
		return redo;
	}
	
	public void setRedo(int redo) {
		this.redo = redo;
	}
	
	public int getRedoIntervalSeconds() {
		return redoIntervalSeconds;
	}
	
	public void setRedoIntervalSeconds(int redoIntervalSeconds) {
		this.redoIntervalSeconds = redoIntervalSeconds;
	}
	
	public boolean isRootStep() {
		return isRootStep;
	}
	
	public void setRootStep(boolean isRootStep) {
		this.isRootStep = isRootStep;
	}
	protected JdbcTemplate getJdbcTemplate(){
		return new JdbcTemplate();
	}
	
	public String toString(){
		return "{id:"+id+",name:"+name+",class:"+this.getClass().getName()+"}";
	}
	
	public String variableSubstitution(String text){
		return variableSubstitution(text, null);
	}
	public int variableSubstitutionInt(String text){
		String rtn=variableSubstitution(text);
		try{
			int rtnInt=Integer.parseInt(rtn);
			return rtnInt;
		}catch(Exception e){
			return 0;
		}
	}
	
	public String variableSubstitution(String text,Map<String,Object> appendData){
		if(appendData!=null && appendData.size()>0){
			appendData.putAll(getVariables());
			return DpExecutorUtils.variableSubstitution(text,appendData);
		}else{
			return DpExecutorUtils.variableSubstitution(text, getVariables());
		}
		
	}
	public boolean isSkipFlag() {
		return skipFlag;
	}
	public void setSkipFlag(boolean skipFlag) {
		this.skipFlag = skipFlag;
	}
	public String getStep_code() {
		return step_code;
	}
	public void setStep_code(String step_code) {
		this.step_code = step_code;
	}
	protected Object clone() throws CloneNotSupportedException {

		StepMeta metaInstance = (StepMeta) super.clone();

		return metaInstance;

	}
	public String getSession_id() {
		return session_id;
	}
	public void setSession_id(String session_id) {
		this.session_id = session_id;
	}
	
}
